﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Client.Panels
{
    public abstract class BasePanel : MyPanel.IPanel
    {
        public List<string> panelHeader = new List<string>();
        protected int indexColumn = 0;
        protected bool speakIndexColumn = true;//是否朗读索引列
        protected bool isSpeakHeader = true;//用光标导航时是否朗读表头
        private bool isSpeakHeadOnPressKey = true;//按下键盘快捷键听取数据时是否朗读对应项目的名称
        protected abstract string[] parentsName { get; }

        protected Dictionary<string, MethodInfo> hotKeyTable = new Dictionary<string, MethodInfo>();
        //protected List<MethodInfo> fields = new List<MethodInfo>();
        protected List<PropertyInfo> fields = new List<PropertyInfo>();
        protected string sortField = "changepercent";
        public bool isTemp { get; set; }

        public override string panelName => this.GetType().Name;

        protected string clientText;

        public BasePanel(string clientText)
        {
            RegisterHotkey("BasePanel");
            InitColumn();
            isTemp = false;
            this.clientText = clientText;
        }


        protected virtual void InitColumn()
        {
            var l = Managers.Manager.jargonM.GetPanelColumns(panelName);
            for (int i = 0; i < l.Length; i++)
            {
                string str = l[i].Trim(' ');
                panelHeader.Add(Managers.Manager.jargonM.GetJargon(str));
            }
        }

        public virtual void Up()
        {
            y = y - 1;
            SpeakCell();
        }

        public virtual void Down()
        {
            y = y + 1;
            SpeakCell();
        }

        public virtual void Left()
        {
            x = x - 1;
            SpeakCell(false);
        }

        public virtual void Right()
        {
            x = x + 1;
            SpeakCell(false);
        }

        public virtual void PageUp()
        {
            y = y - 20;
            SpeakCell();
        }

        public virtual void PageDown()
        {
            y = y + 20;
            SpeakCell();
        }

        public virtual void FirstItem()
        {
            y = 0;
            SpeakCell();
        }

        public virtual void LastItem()
        {
            y = items.Count - 1;
            SpeakCell();
        }

        public virtual void Enter()
        {
            if (Managers.Manager.hotIndex != null)
                StockMenuFuncs.OpenTickView(Managers.Manager.hotIndex);
            else if(Managers.Manager.hotStockInfo!=null)
                StockMenuFuncs.OpenTickView(Managers.Manager.hotStockInfo);
        }

        public void Back()
        {
            Managers.Manager.panelM.RemovePanel();
        }

        public void SpeakCell(bool UpDown = true)
        {
            var cell = this[y, x];
            if (cell == null)
                return;

            string speakStr = "";
            if (horizontal)
            {
                if (speakIndexColumn && UpDown && x != indexColumn)
                    speakStr = this[y, indexColumn].text;
                else if (isSpeakHeader && !UpDown)
                    speakStr = panelHeader[x];
            }
            else
            {
                if (speakIndexColumn && !UpDown && x != indexColumn)
                    speakStr = this[y, indexColumn].text;
                else if (isSpeakHeader && UpDown)
                    speakStr = panelHeader[y];
            }

            speakStr += "，" + cell.text + "。";
            if (UpDown)
                speakStr += GetYPositionString();
            else
                speakStr += GetXPositionString();
            Managers.Manager.ttsM.Speak(speakStr);
        }

        protected virtual void UpdatePanel()
        {
            //在子类构造时必须先调用FillFields，否则以下代码无效

        }

        //protected virtual void FirstUpdate() { }

        protected void UpdatePanel<T>(T[] data)
        {
            items = new List<MyPanel.Item>(data.Length);

            foreach (T i in data)
            {
                var it = new MyPanel.Item();
                foreach (var j in fields)
                {
                    var o = j.GetGetMethod().Invoke(i, null);
                    if (Regex.IsMatch(j.Name, @"trade|open|close|high|low|(ma\d+)"))
                        it.AddCell(o.ToString());
                    else
                        it.AddCell(ToText(o));
                }
                items.Add(it);
            }
        }

        protected void RegisterHotkey(string sectionName)
        {
            var t = this.GetType();

            Dictionary<string, string> hotkeys;
            if (Managers.Manager.hotkeyM.hotKeys.TryGetValue(sectionName, out hotkeys))
            {
                foreach (var i in hotkeys)
                {
                    var m = t.GetMethod(i.Value, BindingFlags.Instance | BindingFlags.Public);
                    if (m != null)
                        hotKeyTable[i.Value] = m;
                }
            }
            else
            {
                Console.WriteLine("没有：" + sectionName + "热键节点");
            }
        }

        public virtual void OnKeyDown(System.Windows.Forms.KeyEventArgs key)
        {
            Managers.Manager.ttsM.Stop();
            string funcName = Managers.Manager.hotkeyM.GetFuncName(this.GetType().Name, key, parentsName);
            if (funcName != "" && hotKeyTable.ContainsKey(funcName))
                hotKeyTable[funcName].Invoke(this, null);
        }

        public virtual void OnAwake()
        {
            XBorder += Managers.Manager.beepM.PlayXBorder;
            YBorder += Managers.Manager.beepM.PlayYBorder;
            NoItem += Managers.Manager.beepM.PlayNoItem;
            OnForeground();
        }
        public virtual void OnSleep()
        {
            OnBackground();
            ClearCron();
        }
        public virtual void OnForeground()
        {
            YChanged += UpdateHotStockInfo;
            Managers.Manager.cronM.firstUpdateSuccessfully += Managers.Manager.beepM.PlaySuccessed;
            string text = clientText + " | " + MyConst.StaticString.APPNAME;
            Managers.Manager.clientForm.Text = text;
            Managers.Manager.clientForm.AccessibleName = text;
            Managers.Manager.clientForm.dataGridView1.AccessibleDescription = clientText;
        }
        public virtual void OnBackground()
        {
            YChanged -= UpdateHotStockInfo;
            Managers.Manager.cronM.firstUpdateSuccessfully -= Managers.Manager.beepM.PlaySuccessed;
        }

        protected string ToText(object obj)
        {
            if (obj == null)
                return "";
            string res = null;
            var t = obj.GetType();
            if (t == typeof(string))
                res = (string)obj;
            else if (t == typeof(DateTime))
                res = timeToText((DateTime)obj);
            else if (t == typeof(int))
            {
                int temp = (int)obj;
                if (temp >= 100000000)
                    res = (temp / 100000000.0f).ToString("F2") + "亿";
                else if (temp >= 10000)
                    res = (temp / 10000.0f).ToString("F2") + "万";
                else
                    res = temp.ToString();
            }
            else if (t == typeof(float))
            {
                float temp = (float)obj;
                if (temp >= 100000000)
                    res = (temp / 100000000).ToString("F2") + "亿";
                else if (temp >= 10000)
                    res = (temp / 10000).ToString("F2") + "万";
                else
                    res = temp.ToString("F2");
            }
            return res;
        }

        protected virtual string timeToText(DateTime time)
        {
            return time.ToString("M月d日, yyyy年");
        }

        protected void FillFields<T>(string sectionName)
        {
            var l = Managers.Manager.jargonM.GetPanelColumns(sectionName);
            var tp = typeof(T);
            foreach (string str in l)
            {
                var pInfo = tp.GetProperty(str, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
                if (pInfo != null)
                    fields.Add(pInfo);
            }
        }

        protected virtual sourceT[] Sort<sourceT, sortT>(string sortField, sourceT[] dataArray, bool des = true) where sortT : IComparable
        {
            var fieldsA = Managers.Manager.jargonM.GetPanelColumns(panelName);
            for (int i = 0; i < fieldsA.Length; i++)
            {
                if (fieldsA[i] == sortField)
                {
                    bool isExchange;
                    for (int j = 0; j < dataArray.Length - 1; j++)
                    {
                        isExchange = false;
                        for (int k = 0; k < dataArray.Length - 1 - j; k++)
                        {
                            var a = (sortT)fields[i].GetGetMethod().Invoke(dataArray[k], null);
                            var b = (sortT)fields[i].GetGetMethod().Invoke(dataArray[k + 1], null);
                            if (des && a.CompareTo(b) < 0)
                            {
                                var temp = dataArray[k];
                                dataArray[k] = dataArray[k + 1];
                                dataArray[k + 1] = temp;
                                isExchange = true;
                            }
                            else if (!des && a.CompareTo(b) > 0)
                            {
                                var temp = dataArray[k];
                                dataArray[k] = dataArray[k + 1];
                                dataArray[k + 1] = temp;
                                isExchange = true;
                            }
                        }
                        if (!isExchange)
                            break;
                    }
                    break;
                }
            }

            return dataArray;
        }
        protected virtual string GetYPositionString()
        {
            string str;
            if (horizontal)
                str = this.items.Count + "之" + (y + 1) + "项";
            else
                str = this.items[y].Count + "之" + (y + 1) + "项";
            return str;
        }
        protected virtual string GetXPositionString()
        {
            string str;
            if(horizontal)
                str = this.items[y].Count + "之" + (x + 1) + "项";
            else
                str = this.items.Count + "之" + (x + 1) + "项";
            return str;
        }

        protected abstract void UpdateHotStockInfo();
        /// <summary>
        /// 清理循环管理器中添加的需要循环获取的内容
        /// </summary>
        protected abstract void ClearCron();
        


        //=========================

        #region QuickSpeak
        public virtual void SpeakCode()
        {
            QuickSpeakData("code", Managers.Manager.hotStockInfo?.code);
        }
        public virtual void SpeakTrade()
        {
            QuickSpeakData("trade", Managers.Manager.hotStockInfo?.trade.ToString("F2"));
        }
        public virtual void SpeakChangepercent()
        {
            QuickSpeakData("changepercent", Managers.Manager.hotStockInfo?.changepercent.ToString("F2"));
        }
        public virtual void SpeakOpen()
        {
            QuickSpeakData("open", Managers.Manager.hotStockInfo?.open.ToString("F2"));
        }
        public virtual void SpeakHigh()
        {
            QuickSpeakData("high", Managers.Manager.hotStockInfo?.high.ToString("F2"));
        }
        public virtual void SpeakLow()
        {
            QuickSpeakData("low", Managers.Manager.hotStockInfo?.low.ToString("F2"));
        }
        public virtual void SpeakPreclose()
        {
            QuickSpeakData("preclose", Managers.Manager.hotStockInfo?.preclose.ToString("F2"));
        }
        public virtual void SpeakAverage()
        {
            QuickSpeakData("average", Managers.Manager.hotStockInfo?.average.ToString("F2"));
        }
        public virtual void SpeakZT()
        {
            QuickSpeakData("zt", Managers.Manager.hotStockInfo?.zt.ToString("F2"));
        }
        public virtual void SpeakDT()
        {
            QuickSpeakData("dt", Managers.Manager.hotStockInfo?.dt.ToString("F2"));
        }
        public virtual void SpeakQRR()
        {
            QuickSpeakData("qrr", Managers.Manager.hotStockInfo?.qrr.ToString("F2"));
        }
        public virtual void SpeakCMT()
        {
            QuickSpeakData("cmt", Managers.Manager.hotStockInfo?.cmt.ToString("F2"));
        }
        public virtual void SpeakTurnover()
        {
            QuickSpeakData("turnover", Managers.Manager.hotStockInfo?.turnover.ToString("F2"));
        }
        public virtual void SpeakAmplitude()
        {
            QuickSpeakData("amplitude", Managers.Manager.hotStockInfo?.amplitude.ToString("F2"));
        }
        public virtual void SpeakVol()
        {
            QuickSpeakData("vol", Managers.Manager.hotStockInfo?.vol.ToString());
        }
        public virtual void SpeakAmount()
        {
            QuickSpeakData("amount", Managers.Manager.hotStockInfo?.amount.ToString("F2"));
        }
        public virtual void SpeakOutvol()
        {
            QuickSpeakData("outvol", Managers.Manager.hotStockInfo?.outvol.ToString());
        }
        public virtual void SpeakInvol()
        {
            QuickSpeakData("invol", Managers.Manager.hotStockInfo?.invol.ToString());
        }
        public virtual void SpeakCirculatingShares()
        {
            QuickSpeakData("circulatingShares", Managers.Manager.hotStockInfo?.circulatingShares.ToString("F2"));
        }
        public virtual void SpeakCirculatingAmount()
        {
            QuickSpeakData("circulatingAmount", Managers.Manager.hotStockInfo?.circulatingAmount.ToString("F2"));
        }
        public virtual void SpeakTotalShares()
        {
            QuickSpeakData("totalShares", Managers.Manager.hotStockInfo?.totalShares.ToString("F2"));
        }
        public virtual void SpeakTotalAmount()
        {
            QuickSpeakData("totalAmount", Managers.Manager.hotStockInfo?.totalAmount.ToString("F2"));
        }
        public virtual void SpeakPE()
        {
            QuickSpeakData("pe", Managers.Manager.hotStockInfo?.pe.ToString("F2"));
        }
        public virtual void SpeakSPE()
        {
            QuickSpeakData("spe", Managers.Manager.hotStockInfo?.spe.ToString("F2"));
        }
        public virtual void SpeakTTM()
        {
            QuickSpeakData("ttm", Managers.Manager.hotStockInfo?.ttm.ToString("F2"));
        }
        public virtual void SpeakPB()
        {
            QuickSpeakData("pb", Managers.Manager.hotStockInfo?.pb.ToString("F2"));
        }
        public virtual void SpeakBuy1()
        {
            QuickSpeakData("buy1", Managers.Manager.hotStockInfo?.buy1.ToString("F2"));
        }
        public virtual void SpeakBuy1Vol()
        {
            QuickSpeakData("buy1vol", Managers.Manager.hotStockInfo?.buy1vol.ToString());
        }
        public virtual void SpeakBuy2()
        {
            QuickSpeakData("buy2", Managers.Manager.hotStockInfo?.buy2.ToString("F2"));
        }
        public virtual void SpeakBuy2Vol()
        {
            QuickSpeakData("buy2vol", Managers.Manager.hotStockInfo?.buy2vol.ToString());
        }
        public virtual void SpeakBuy3()
        {
            QuickSpeakData("buy3", Managers.Manager.hotStockInfo?.buy3.ToString("F2"));
        }
        public virtual void SpeakBuy3Vol()
        {
            QuickSpeakData("buy3vol", Managers.Manager.hotStockInfo?.buy3vol.ToString());
        }
        public virtual void SpeakBuy4()
        {
            QuickSpeakData("buy4", Managers.Manager.hotStockInfo?.buy4.ToString("F2"));
        }
        public virtual void SpeakBuy4Vol()
        {
            QuickSpeakData("buy4vol", Managers.Manager.hotStockInfo?.buy4vol.ToString());
        }
        public virtual void SpeakBuy5()
        {
            QuickSpeakData("buy5", Managers.Manager.hotStockInfo?.buy5.ToString("F2"));
        }
        public virtual void SpeakBuy5Vol()
        {
            QuickSpeakData("buy5vol", Managers.Manager.hotStockInfo?.buy5vol.ToString());
        }
        public virtual void SpeakSell1()
        {
            QuickSpeakData("sell1", Managers.Manager.hotStockInfo?.sell1.ToString("F2"));
        }
        public virtual void SpeakSell1Vol()
        {
            QuickSpeakData("sell1vol", Managers.Manager.hotStockInfo?.sell1vol.ToString());
        }
        public virtual void SpeakSell2()
        {
            QuickSpeakData("sell2", Managers.Manager.hotStockInfo?.sell2.ToString("F2"));
        }
        public virtual void SpeakSell2Vol()
        {
            QuickSpeakData("sell2vol", Managers.Manager.hotStockInfo?.sell2vol.ToString());
        }
        public virtual void SpeakSell3()
        {
            QuickSpeakData("sell3", Managers.Manager.hotStockInfo?.sell3.ToString("F2"));
        }
        public virtual void SpeakSell3Vol()
        {
            QuickSpeakData("sell3vol", Managers.Manager.hotStockInfo?.sell3vol.ToString());
        }
        public virtual void SpeakSell4()
        {
            QuickSpeakData("sell4", Managers.Manager.hotStockInfo?.sell4.ToString("F2"));
        }
        public virtual void SpeakSell4Vol()
        {
            QuickSpeakData("sell4vol", Managers.Manager.hotStockInfo?.sell4vol.ToString());
        }
        public virtual void SpeakSell5()
        {
            QuickSpeakData("sell5", Managers.Manager.hotStockInfo?.sell5.ToString("F2"));
        }
        public virtual void SpeakSell5Vol()
        {
            QuickSpeakData("sell5vol", Managers.Manager.hotStockInfo?.sell5vol.ToString());
        }

        protected void QuickSpeakData(string head, string text)
        {
            if (text != null)
            {
                var jargon = Managers.Manager.jargonM.GetJargon(head);
                if (isSpeakHeadOnPressKey)
                    Managers.Manager.ttsM.Speak(jargon + text);
                else
                    Managers.Manager.ttsM.Speak(text);
            }
        }
        #endregion

        //======================

        #region Menu
        public void OpenTickView()
        {
            StockMenuFuncs.OpenTickView(GetHotInfo());
        }
        public void OpenKView()
        {
            StockMenuFuncs.OpenKlineView(GetHotInfo());
        }
        public void AddZXG()
        {
            Managers.Manager.zxgM.AddZXG(Managers.Manager.hotStockInfo);
        }
        public void RemoveZXG()
        {
            Managers.Manager.zxgM.removeZXG(Managers.Manager.hotStockInfo);
        }
        public void OpenNews()
        {
            StockMenuFuncs.OpenNews(GetHotInfo());
        }
        public void OpenGeneralInfomation()
        {
            StockMenuFuncs.OpenGeneralInfomation();
        }
        public void QuickAddZXG()
        {
            if (Managers.Manager.hotStockInfo != null)
                Managers.Manager.zxgM.AddStock(Managers.Manager.hotStockInfo.symbol);
        }
        public void ChoiceKTime()
        {
            StockMenuFuncs.ChoiceKTime(GetHotInfo());
        }

        DataCenter.Models.IInfo GetHotInfo()
        {
            if (Managers.Manager.hotIndex != null)
                return Managers.Manager.hotIndex;
            if (Managers.Manager.hotStockInfo != null)
                return Managers.Manager.hotStockInfo;
            return null;
        }
        #endregion
    }
}
